#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
#include <fcntl.h>
#include <sys/wait.h>

#define BUFSIZE 1024
int progress = 0; // 进度
int exit_flag = 1;
char *path1 = "./1.text";
char *path2 = "./2.text";

void send_printf(int signo)
{
  int ret;
  ret = kill(getppid(), SIGUSR1);
  if (ret < 0)
  {
    perror("发送信号失败");
    exit(1);
  }
  return;
}

void printf_progress(int signo)
{
  printf("进度:%d%%\n", progress * 100 / (getFileSize(path1) / BUFSIZE + 1));
  return;
}

int getFileSize(char *path)
{
  // 获取文件大小
  int fd;
  struct stat buf;
  fd = open(path, O_RDONLY);
  if (fd < 0)
  {
    perror("打开文件失败");
    exit(1);
  }
  fstat(fd, &buf);
  close(fd);
  return buf.st_size;
}

int main()
{
  int ret;
  pid_t pid;

  if ((pid = fork()) > 0)
  { // 父进程

    int fd1, fd2, count;
    char buf[BUFSIZE];

    // 先要注册信号处理函数
    struct sigaction act, oldact;
    act.sa_handler = printf_progress;  // 信号处理函数
    act.sa_flags = 0;                  // 默认信号处理方式
    sigemptyset(&act.sa_mask);         // 清空信号集
    sigaction(SIGUSR1, &act, &oldact); // 注册信号处理函数

    // 拷贝文件
    fd1 = open(path1, O_RDONLY); // 读文件
    if (fd1 < 0)
    {
      perror("打开读文件失败");
      exit(1);
    }

    fd2 = open(path2, O_WRONLY | O_CREAT, 0644); // 写文件,不存在则创建
    if (fd2 < 0)
    {
      perror("打开写文件失败");
      exit(1);
    }

    while ((count = read(fd1, buf, BUFSIZE)) > 0)
    {
      progress++;             // 进度+1
      write(fd2, buf, count); // 写文件
      sleep(1);               // 暂停一秒,方便观察效果
    }
    printf("文件拷贝完成\n");
    close(fd1);
    close(fd2);
    // 拷贝结束,发送信号结束子进程
    ret = kill(pid, SIGKILL);
    if (ret < 0)
    {
      perror("发送信号失败");
      exit(1);
    }
    // 通知子进程退出
    exit_flag = 0;

    ret = waitpid(pid, NULL, 0);
    if (ret <= 0)
    {
      perror("子进程退出失败");
    }
  }
  else if (pid == 0)
  { // 子进程
    // 向父进程发送信号
    // 定时器,定时向子进程发射信号
    struct itimerval timer, oldtimer;
    timer.it_value.tv_sec = 1; // 起始时间1s
    timer.it_value.tv_usec = 0;

    timer.it_interval.tv_sec = 1; // 间隔时间1s
    timer.it_interval.tv_usec = 0;

    setitimer(ITIMER_REAL, &timer, &oldtimer); // 设置定时器

    struct sigaction act, oldact;
    act.sa_handler = send_printf; // 信号处理函数
    act.sa_flags = 0;             // 默认信号处理方式
    sigemptyset(&act.sa_mask);    // 清空信号集

    sigaction(SIGALRM, &act, &oldact); // 注册信号处理函数
    while (exit_flag)
    {
      // 循环等待
      pause(); // 休眠等待,等待一个信号
    }
    printf("子进程退出\n");
    exit(0);
  }
  else
  { // fork失败
    perror("fork error");
    exit(1);
  }
}